#pragma once
#include "thread/activeresult.hpp"
#include "thread/activerunnable.hpp"
#include "thread/activestarter.hpp"
#include "utils/autoptr.hpp"
using namespace JHCPP::utils;

namespace JHCPP
{
	namespace thread
	{
		template <class T, class ArgType, class OwnerType, class StarterType = TActiveStarter<OwnerType> >
		class TActiveMethod
		{
		public:
			typedef T (OwnerType::*Callback)(const ArgType&);
			typedef TActiveResult<T> ActiveResultType;
			typedef TActiveRunnable<T, ArgType, OwnerType> ActiveRunnableType;

			TActiveMethod(OwnerType* pOwner, Callback method) : m_pOwner(pOwner), m_method(method)
			{
				jh_check_ptr (pOwner);
			}

			ActiveResultType operator () (const ArgType& arg)
			{
				ActiveResultType result(new TActiveResultHolder<T>());
				CActiveRunnableBase::Ptr pRunnable(new ActiveRunnableType(m_pOwner, m_method, arg, result));
				StarterType::start(m_pOwner, pRunnable);
				return result;
			}

			TActiveMethod(const TActiveMethod& other) : m_pOwner(other.m_pOwner), m_method(other.m_method)
			{
			}

			TActiveMethod& operator = (const TActiveMethod& other)
			{
				TActiveMethod tmp(other);
				swap(tmp);
				return *this;
			}

			void swap(TActiveMethod& other)
			{
				std::swap(m_pOwner, other.m_pOwner);
				std::swap(m_method, other.m_method);
			}

		private:
			TActiveMethod();

			OwnerType* m_pOwner;
			Callback   m_method;
		};



		template <class T, class OwnerType, class StarterType>
		class TActiveMethod <T, void, OwnerType, StarterType>
		{
		public:
			typedef T (OwnerType::*Callback)(void);
			typedef TActiveResult<T> ActiveResultType;
			typedef TActiveRunnable<T, void, OwnerType> ActiveRunnableType;

			TActiveMethod(OwnerType* pOwner, Callback method) : m_pOwner(pOwner), m_method(method)
			{
				jh_check_ptr (pOwner);
			}

			ActiveResultType operator () (void)
			{
				ActiveResultType result(new TActiveResultHolder<T>());
				CActiveRunnableBase::Ptr pRunnable(new ActiveRunnableType(m_pOwner, m_method, result));
				StarterType::start(m_pOwner, pRunnable);
				return result;
			}

			TActiveMethod(const TActiveMethod& other) : m_pOwner(other.m_pOwner), m_method(other.m_method)
			{
			}

			TActiveMethod& operator = (const TActiveMethod& other)
			{
				TActiveMethod tmp(other);
				swap(tmp);
				return *this;
			}

			void swap(TActiveMethod& other)
			{
				std::swap(m_pOwner, other.m_pOwner);
				std::swap(m_method, other.m_method);
			}

		private:
			TActiveMethod();

			OwnerType* m_pOwner;
			Callback   m_method;
		};
	}//end of namespace thread
}//end of namespace JHCPP
